package com.munhrasoft.dinamica.managedbeans;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.AjaxBehaviorEvent;

import net.sf.jasperreports.engine.JRException;

import com.munhra.dinamica.reports.Reports;
import com.munhrasoft.dinamica.business.entities.CheckListHeader;
import com.munhrasoft.dinamica.business.entities.CheckListLines;
import com.munhrasoft.dinamica.business.entities.Cliente;
import com.munhrasoft.dinamica.business.entities.Corretor;
import com.munhrasoft.dinamica.business.entities.Custo;
import com.munhrasoft.dinamica.business.entities.GrupoPassos;
import com.munhrasoft.dinamica.business.entities.Imovel;
import com.munhrasoft.dinamica.business.entities.ParametrosCusto;
import com.munhrasoft.dinamica.business.entities.PassosProcesso;
import com.munhrasoft.dinamica.business.entities.Processo;
import com.munhrasoft.dinamica.business.entities.ProcessoAcompanha;
import com.munhrasoft.dinamica.business.entities.ProcessoCheckList;
import com.munhrasoft.dinamica.business.entities.ProcessoChkHeader;
import com.munhrasoft.dinamica.business.entities.ProcessoStatus;
import com.munhrasoft.dinamica.business.entities.Vendedor;
import com.munhrasoft.dinamica.business.logic.CheckListEJB;
import com.munhrasoft.dinamica.business.logic.ClienteEJB;
import com.munhrasoft.dinamica.business.logic.CorretorEJB;
import com.munhrasoft.dinamica.business.logic.CustoEJB;
import com.munhrasoft.dinamica.business.logic.GrupoPassosEJB;
import com.munhrasoft.dinamica.business.logic.ParametrosEJB;
import com.munhrasoft.dinamica.business.logic.ProcessoEJB;
import com.munhrasoft.dinamica.business.logic.VendedorEJB;
import com.munhrasoft.dinamica.viewmodels.CapaProcesso;
import com.munhrasoft.dinamica.viewmodels.CheckListPerGroup;
import com.munhrasoft.dinamica.viewmodels.PassosPorGrupo;

@ManagedBean
@ViewScoped
public class ProcessoController {

    @EJB
    private ClienteEJB              clienteEJB;
    @EJB
    private VendedorEJB             vendedorEJB;
    @EJB
    private CorretorEJB             corretorEJB;
    @EJB
    private ProcessoEJB             processoEJB;
    @EJB
    private CheckListEJB            checkListEJB;
    @EJB
    private ParametrosEJB           parametrosEJB;
    @EJB
    private CustoEJB                custoEJB;
    @EJB
    private GrupoPassosEJB          grupoPassosEJB;

    private Processo                processo;
    private Cliente                 selectedCliente;
    private Vendedor                selectedVendedor;
    private Corretor                selectedCorretor;
    private Imovel                  selectedImovel;
    private CapaProcesso            capaProcesso;

    private List<Cliente>           clienteSuggestions;
    private List<Vendedor>          vendedorSuggestions;
    private List<Corretor>          corretorSuggestions;
    private List<CheckListPerGroup> chklistPerGroup;
    private List<Processo>          listaProcessos;
    private List<GrupoPassos>       listaGPassos;

    private List<String>            listaTipo;
    private List<String>            listaOperacao;
    private List<String>            listaModal1;
    private List<String>            listaModal2;
    private List<String>            listaTitulo;

    private ProcessoCheckList       selectedChkLine;
    private ProcessoAcompanha       selectedAcompLine;

    private String                  titulo;
    private String                  operacao;
    private String                  tipo;
    private String                  modalidade1;
    private String                  modalidade2;
    private boolean                 checkListRendered;
    private boolean                 criaProcessoRendered;
    private boolean                 processoRendered;

    private static Logger           logger = Logger.getLogger(ProcessoController.class.getName());

    @PostConstruct
    public void init() {
        logger.info("PostConstruct init");
        processo = new Processo();

        processo.setPchkheader(new ProcessoChkHeader());
        this.setCheckListRendered(false);
        this.setCriaProcessoRendered(true);
        this.setProcessoRendered(false);

        listaTipo = new ArrayList<String>();
        listaOperacao = new ArrayList<String>();
        listaModal1 = new ArrayList<String>();
        listaModal2 = new ArrayList<String>();
        listaTitulo = new ArrayList<String>();

        this.setListaGPassos(grupoPassosEJB.pegaTodosGrupos());
        this.completaInfoProcesso();

    }

    private void completaInfoProcesso() {
        logger.info("Completa Filtro ChkHeader");

        List<CheckListHeader> chkHeaderList = checkListEJB.fetchAllChkList();

        listaTipo.add("NOVO");
        listaTipo.add("USADO");

        listaOperacao.add("AQUISIÇÃO");
        listaOperacao.add("CONSTRUÇÃO");

        listaModal1.add("CCFGTS");
        listaModal1.add("CCSBPE");

        listaModal2.add("RESIDENCIAL");
        listaModal2.add("TERRENO");

        for (CheckListHeader chkHeader : chkHeaderList) {

            listaTitulo.add(chkHeader.getTitulo());

            /*
             * if (!verificaSeExiste(listaTipo, chkHeader.getTipo())) {
             * listaTipo.add(chkHeader.getTipo()); }
             * 
             * if (!verificaSeExiste(listaOperacao, chkHeader.getOperacao())) {
             * listaOperacao.add(chkHeader.getOperacao()); }
             * 
             * if (!verificaSeExiste(listaModal1, chkHeader.getModalidade1())) {
             * listaModal1.add(chkHeader.getModalidade1()); }
             * 
             * if (!verificaSeExiste(listaModal2, chkHeader.getModalidade2())) {
             * listaModal2.add(chkHeader.getModalidade2()); }
             */

        }

        logger.info("Lista Tipo " + listaTipo.size());
        logger.info("Lista Oper " + listaOperacao.size());
        logger.info("Lista Modal1 " + listaModal1.size());
        logger.info("Lista Modal2 " + listaModal2.size());

    }

    /*
     * private boolean verificaSeExiste(List<String> lista, String valor) { for (String str : lista)
     * { if (str.equals(valor)) { return true; } } return false; }
     */

    private void completaCapaProcesso() {
        capaProcesso = new CapaProcesso();
        capaProcesso.setCliente(processo.getCliente());
        capaProcesso.setCorretor(processo.getCorretor());
        capaProcesso.setProcuradorCliente(processo.getProcuradorCliente());
        capaProcesso.setProcuradorVendedor(processo.getProcuradorVendedor());
        capaProcesso.setVendedor(processo.getVendedor());

        List<PassosPorGrupo> passosGrupoList = new ArrayList<PassosPorGrupo>();

        for (GrupoPassos gpassos : listaGPassos) {
            PassosPorGrupo passosGrupo = new PassosPorGrupo();
            passosGrupo.setGrupo(gpassos.getTitulo());

            List<ProcessoAcompanha> acompList = new ArrayList<ProcessoAcompanha>();

            for (PassosProcesso passos : gpassos.getPassos()) {

                ProcessoAcompanha pacompanha = new ProcessoAcompanha();

                // vai ter que pegar os dados do processo aqui para mostrar na UI, vai ter
                // que fazer uma busca em todos os passos que foram incluidos no acompanhamento
                // do processo, se possuir mais de um mesmo passo sempre pegar o mais novo,
                // por hora vou fazer penas a casca, ou seja nao vou pegar nada do processo
                // ainda.

                pacompanha.setData(null);
                pacompanha.setGpassos(gpassos);
                pacompanha.setPassos(passos);
                pacompanha.setPasso(passos.getDescricao());

                acompList.add(pacompanha);

            }

            passosGrupo.setAcompanhaLines(acompList);
            passosGrupoList.add(passosGrupo);

        }

        capaProcesso.setPassosPorGrupo(passosGrupoList);
    }

    private void saveChkListPerGroup() {
        // chamar antes de salvar para incluir no objeto processo os campos que
        // estao desmembrados

        processo.getProcessoChkLine().clear();

        for (CheckListPerGroup chkPerGroup : chklistPerGroup) {

            for (ProcessoCheckList pchk : chkPerGroup.getCheckListItems()) {

                processo.getProcessoChkLine().add(pchk);

            }

        }

    }

    private void fillchkListPerGroup() {
        // processo.getProcessoChkLine()
        HashMap<String, List<ProcessoCheckList>> groupedHash = new HashMap<String, List<ProcessoCheckList>>();
        chklistPerGroup = new ArrayList<CheckListPerGroup>();

        for (ProcessoCheckList pchk : processo.getProcessoChkLine()) {
            if (groupedHash.get(pchk.getGrupo()) == null) {
                // cria lista pois ainda nao tem nenhum elemento
                groupedHash.put(pchk.getGrupo(), new ArrayList<ProcessoCheckList>());
                groupedHash.get(pchk.getGrupo()).add(pchk);
            } else {
                // a lista pois ja tem elemento
                groupedHash.get(pchk.getGrupo()).add(pchk);
            }
        }

        // com os dados separados no hash vamos criar os objetos para o
        // accordion

        for (String groupKey : groupedHash.keySet()) {
            logger.info("Group name " + groupKey);
            CheckListPerGroup chkpergroup = new CheckListPerGroup();
            chkpergroup.setGroup(groupKey);
            chkpergroup.setCheckListItems(groupedHash.get(groupKey));
            chklistPerGroup.add(chkpergroup);
        }

    }

    public void trocaProcesso() {
        fillchkListPerGroup();
        completaCapaProcesso();
        logger.info("Troca de processo processo selecionado "
                + this.getProcesso().getTituloProcesso());
    }

    public void inserePasso(ActionEvent actionEvent) {
        logger.info("Insere passo");
        ProcessoAcompanha pacomp = new ProcessoAcompanha();
        pacomp.setData(new Date());
        processo.getAcompanhaLines().add(pacomp);
        processoEJB.updateProcesso(processo);
        showMessage(FacesMessage.SEVERITY_INFO, "Operação concluída", "Passo inserido");
    }

    public void removePasso(ActionEvent actionEvent) {
        logger.info("Remove passo");
        if (selectedAcompLine != null) {
            processo.getAcompanhaLines().remove(selectedAcompLine);
            processoEJB.updateProcesso(processo);
        } else {
            showMessage(FacesMessage.SEVERITY_INFO, "Operação não realizada", "Selecione uma linha");
        }
    }

    public void pesquisaProcesso(ActionEvent actionEvent) {
        logger.info("Pesquisa processo para o cliente " + selectedCliente.getProponente());

        this.setListaProcessos(processoEJB.findProcessoByCliente(selectedCliente));

        logger.info("Processo encontrado" + this.getListaProcessos().get(0).getProcesso_id());

        if (!this.getListaProcessos().isEmpty()) {
            processo = this.getListaProcessos().get(0);
            fillchkListPerGroup();
            completaCapaProcesso();
            this.setProcessoRendered(true);
        } else {
            showMessage(FacesMessage.SEVERITY_INFO, "Operação Concluída",
                    "Nenhum processo encontrado");
        }
    }

    public void salvarProcesso(ActionEvent actionEvent) {
        logger.info("Salva processo");
        saveChkListPerGroup();
        processo = processoEJB.updateProcesso(processo);
        fillchkListPerGroup();
        showMessage(FacesMessage.SEVERITY_INFO, "Operação Concluída", "Processo salvo com sucesso");
    }

    public void calculaCusto(ActionEvent actionEvent) {
        logger.info("Calcula custo");
        showMessage(FacesMessage.SEVERITY_INFO, "Operação concluída", "Custo calculado");

        custoEJB.calculaCustoProcesso(processo.getCusto(), processo.getPchkheader(),
                processo.isPrimeiroImovel(), processo.getImovel());

    }

    /**
     * Monta um objeto do tipo processo so com o que e nessesario para o relatorio, removendo os
     * campos do checklist que sejam opcionais no relatorio
     * 
     * @return
     */

    private Processo preparaProcessoRelatorio() {
        Processo prelatorio = new Processo();

        prelatorio.setCliente(processo.getCliente());
        List<ProcessoCheckList> plineList = new ArrayList<ProcessoCheckList>();

        for (ProcessoCheckList pcheck : processo.getProcessoChkLine()) {

            if (!pcheck.getOpcional()) {
                plineList.add(pcheck);
            }
        }

        prelatorio.setProcessoChkLine(plineList);
        return prelatorio;
    }

    public void imprimeCapa(ActionEvent actionEvent) throws IOException, JRException {
        logger.info("Imprime Capa de Processo");

        CapaProcesso capa = new CapaProcesso();
        capa.setCliente(processo.getCliente());
        capa.setCorretor(processo.getCorretor());
        capa.setProcuradorVendedor(processo.getProcuradorVendedor());
        capa.setProcuradorCliente(processo.getProcuradorCliente());
        capa.setVendedor(processo.getVendedor());

        Reports.imprimeRelatorioCapa(capa);

    }

    public void imprimePendencias(ActionEvent actionEvent) throws IOException, JRException {

        logger.info("Imprime Pendencias");
        Processo relatProcesso = preparaProcessoRelatorio();
        processoEJB.ordenaPassosPorGrupo(relatProcesso);
        Reports.imprimeRelatorioPendencias(relatProcesso);

    }

    public void createProcesso(ActionEvent actionEvent) {

        // logger.info("Check list search " + operacao + " " + tipo + " " + modalidade1 + " "
        // + modalidade2);
        logger.info("Processo " + processo.getCliente());

        logger.info("Imoveis do cliente " + processo.getCliente().getImoveis().size());

        logger.info("CheckList title " + processo.getPchkheader().getTitulo());

        List<CheckListHeader> chkHeaders = checkListEJB.findChkListByTitulo(processo
                .getPchkheader().getTitulo());

        // List<CheckListHeader> chkHeaders = checkListEJB.findChkListByProcess(operacao, tipo,
        // modalidade1, modalidade2);

        if (!chkHeaders.isEmpty()) {
            logger.info("Criando o processo check list lines "
                    + chkHeaders.get(0).getCheckLines().size());

            processo.setVendedor(selectedVendedor);
            processo.setCorretor(selectedCorretor);
            processo.setImovel(selectedImovel);
            processo.setDataCriacao(new Date());
            processo.setStatus(ProcessoStatus.NOVO);
            // processo.setChkheader(chkHeaders.get(0));

            // ProcessoChkHeader pchkHeader = new ProcessoChkHeader();
            CheckListHeader chkHeader = chkHeaders.get(0);

            // pchkHeader.setModalidade1(chkHeader.getModalidade1());
            // pchkHeader.setModalidade2(chkHeader.getModalidade2());
            // pchkHeader.setOperacao(chkHeader.getOperacao());
            // pchkHeader.setTipo(chkHeader.getTipo());
            // pchkHeader.setTitulo(chkHeader.getTitulo());

            // pchkHeader.setModalidade1(modalidade1);
            // pchkHeader.setModalidade2(modalidade2);
            // pchkHeader.setOperacao(operacao);
            // pchkHeader.setTipo(tipo);
            // pchkHeader.setTitulo(chkHeader.getTitulo());

            // processo.setPchkheader(pchkHeader);

            processo.getPchkheader().setTitulo(chkHeader.getTitulo());

            Custo custo = new Custo();

            ParametrosCusto custoparam = parametrosEJB.pegaParamCusto();
            custo.setParamdesp(custoparam.getDespachante());
            custo.setParamibti((custoparam.getIbti()));
            custo.setParamvmatricula(custoparam.getVmatricula());
            custo.setParampesqcadastral(custoparam.getPesqcadastral());
            custo.setParampremioseguro(custoparam.getPremioseguro());
            custo.setParamtxccfgts(custoparam.getTxccfgts());
            custo.setParamtxccsbte(custoparam.getTxccsbte());

            logger.info("Imovel do processo matricula" + processo.getImovel().getMatricula());
            logger.info("Imovel do processo valor de venda"
                    + processo.getImovel().getValcompvendatotal());

            custoEJB.calculaCustoProcesso(custo, processo.getPchkheader(),
                    processo.isPrimeiroImovel(), processo.getImovel());

            processo.setCusto(custo);

            logger.info("Antes do create");

            logger.info("Depois do create");

            List<ProcessoCheckList> processChk = new ArrayList<ProcessoCheckList>();

            for (CheckListLines chkLines : chkHeaders.get(0).getCheckLines()) {
                ProcessoCheckList pcheckList = new ProcessoCheckList();
                pcheckList.setChecked(false);
                pcheckList.setOpcional(true);
                pcheckList.setDescricao(chkLines.getDescricao());
                pcheckList.setGrupo(chkLines.getGrupo());
                logger.info("Descricao documento " + pcheckList.getDescricao());
                processChk.add(pcheckList);
            }

            processo.setProcessoChkLine(processChk);

            fillchkListPerGroup();

            showMessage(FacesMessage.SEVERITY_INFO, "Operação concluída",
                    "Processo criado com sucesso");
            processo = processoEJB.createProcesso(processo);

            processo.setTituloProcesso("Processo numero " + processo.getProcesso_id());

            processoEJB.updateProcesso(processo);

            // processo.getProcessoChkLine().size()
            logger.info("Linhas do checklist " + processo.getProcessoChkLine().size());

            this.setCheckListRendered(true);
            this.setCriaProcessoRendered(false);

        } else {
            logger.info("Check List Vazio");
            // TODO tipo de processo nao encontrado colocar uma mensagem aqui
            // e tratar o erro

        }
    }

    private void showMessage(Severity sev, String summary, String detail) {
        FacesMessage message = new FacesMessage(sev, summary, detail);
        FacesContext.getCurrentInstance().addMessage(null, message);
    }

    public void atualizaCapa(AjaxBehaviorEvent vlChangeEvent) {
        // processo = processoEJB.updateProcesso(processo);
        completaCapaProcesso();
        logger.info("Atualiza Capa");
    }

    public void changeValue(AjaxBehaviorEvent vlChangeEvent) {
        // processo = processoEJB.updateProcesso(processo);
        logger.info("check box changed");
    }

    public void pegaCheckList(ActionEvent actionEvent) {
        logger.info("pegaCheckListpegaCheckList");
    }

    public List<Cliente> completeCliente(String nomeCliparcial) {
        return clienteEJB.findClientesByName(nomeCliparcial);
    }

    public List<Vendedor> completeVendedor(String nomeVendparcial) {
        return vendedorEJB.findVendedorByName(nomeVendparcial);
    }

    public List<Corretor> completeCorretor(String nomeCorrparcial) {
        return corretorEJB.findCorretorByName(nomeCorrparcial);
    }

    public Processo getProcesso() {
        return processo;
    }

    public void setProcesso(Processo processo) {
        this.processo = processo;
    }

    public Cliente getSelectedCliente() {
        return selectedCliente;
    }

    public void setSelectedCliente(Cliente selectedCliente) {
        this.selectedCliente = selectedCliente;
    }

    public List<Cliente> getClienteSuggestions() {
        return clienteSuggestions;
    }

    public void setClienteSuggestions(List<Cliente> clienteSuggestions) {
        this.clienteSuggestions = clienteSuggestions;
    }

    public Vendedor getSelectedVendedor() {
        return selectedVendedor;
    }

    public void setSelectedVendedor(Vendedor selectedVendedor) {
        this.selectedVendedor = selectedVendedor;
    }

    public Corretor getSelectedCorretor() {
        return selectedCorretor;
    }

    public void setSelectedCorretor(Corretor selectedCorretor) {
        this.selectedCorretor = selectedCorretor;
    }

    public List<Vendedor> getVendedorSuggestions() {
        return vendedorSuggestions;
    }

    public void setVendedorSuggestions(List<Vendedor> vendedorSuggestions) {
        this.vendedorSuggestions = vendedorSuggestions;
    }

    public List<Corretor> getCorretorSuggestions() {
        return corretorSuggestions;
    }

    public void setCorretorSuggestions(List<Corretor> corretorSuggestions) {
        this.corretorSuggestions = corretorSuggestions;
    }

    public String getOperacao() {
        return operacao;
    }

    public void setOperacao(String operacao) {
        this.operacao = operacao;
    }

    public String getTipo() {
        return tipo;
    }

    public void setTipo(String tipo) {
        this.tipo = tipo;
    }

    public String getModalidade1() {
        return modalidade1;
    }

    public void setModalidade1(String modalidade1) {
        this.modalidade1 = modalidade1;
    }

    public String getModalidade2() {
        return modalidade2;
    }

    public void setModalidade2(String modalidade2) {
        this.modalidade2 = modalidade2;
    }

    public ProcessoCheckList getSelectedChkLine() {
        return selectedChkLine;
    }

    public void setSelectedChkLine(ProcessoCheckList selectedChkLine) {
        this.selectedChkLine = selectedChkLine;
    }

    public List<CheckListPerGroup> getChklistPerGroup() {
        return chklistPerGroup;
    }

    public void setChklistPerGroup(List<CheckListPerGroup> chklistPerGroup) {
        this.chklistPerGroup = chklistPerGroup;
    }

    public ProcessoAcompanha getSelectedAcompLine() {
        return selectedAcompLine;
    }

    public void setSelectedAcompLine(ProcessoAcompanha selectedAcompLine) {
        this.selectedAcompLine = selectedAcompLine;
    }

    public boolean isCheckListRendered() {
        return checkListRendered;
    }

    public void setCheckListRendered(boolean checkListRendered) {
        this.checkListRendered = checkListRendered;
    }

    public boolean isCriaProcessoRendered() {
        return criaProcessoRendered;
    }

    public void setCriaProcessoRendered(boolean criaProcessoRendered) {
        this.criaProcessoRendered = criaProcessoRendered;
    }

    public Imovel getSelectedImovel() {
        return selectedImovel;
    }

    public void setSelectedImovel(Imovel selectedImovel) {
        this.selectedImovel = selectedImovel;
    }

    public boolean isProcessoRendered() {
        return processoRendered;
    }

    public void setProcessoRendered(boolean processoRendered) {
        this.processoRendered = processoRendered;
    }

    public List<Processo> getListaProcessos() {
        return listaProcessos;
    }

    public void setListaProcessos(List<Processo> listaProcessos) {
        this.listaProcessos = listaProcessos;
    }

    public List<GrupoPassos> getListaGPassos() {
        return listaGPassos;
    }

    public void setListaGPassos(List<GrupoPassos> listaGPassos) {
        this.listaGPassos = listaGPassos;
    }

    public CapaProcesso getCapaProcesso() {
        return capaProcesso;
    }

    public void setCapaProcesso(CapaProcesso capaProcesso) {
        this.capaProcesso = capaProcesso;
    }

    public List<String> getListaTipo() {
        return listaTipo;
    }

    public void setListaTipo(List<String> listaTipo) {
        this.listaTipo = listaTipo;
    }

    public List<String> getListaOperacao() {
        return listaOperacao;
    }

    public void setListaOperacao(List<String> listaOperacao) {
        this.listaOperacao = listaOperacao;
    }

    public List<String> getListaModal1() {
        return listaModal1;
    }

    public void setListaModal1(List<String> listaModal1) {
        this.listaModal1 = listaModal1;
    }

    public List<String> getListaModal2() {
        return listaModal2;
    }

    public void setListaModal2(List<String> listaModal2) {
        this.listaModal2 = listaModal2;
    }

    public List<String> getListaTitulo() {
        return listaTitulo;
    }

    public void setListaTitulo(List<String> listaTitulo) {
        this.listaTitulo = listaTitulo;
    }

    public String getTitulo() {
        return titulo;
    }

    public void setTitulo(String titulo) {
        this.titulo = titulo;
    }

}
